package com.ruoyi.netty.plc;

import com.ruoyi.netty.protocol.ModbusMessage;
import com.ruoyi.netty.storage.InfluxDBService;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.influxdb.dto.Point;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * PLC数据采集器
 * 支持大批量点位采集
 */
@Component
@Slf4j
public class PlcDataCollector {

    //@Autowired
    private InfluxDBService influxDBService;
    
    // 存储PLC地址映射
    private final Map<String, List<PlcAddress>> deviceAddressMap = new ConcurrentHashMap<>();
    
    // 存储最新的数据
    private final Map<String, Map<Integer, Integer>> latestDataMap = new ConcurrentHashMap<>();
    
    // 事务ID生成器
    private final AtomicInteger transactionIdGenerator = new AtomicInteger(0);
    
    /**
     * 注册PLC地址
     * 
     * @param deviceId 设备ID
     * @param addresses 地址列表
     */
    public void registerAddresses(String deviceId, List<PlcAddress> addresses) {
        deviceAddressMap.put(deviceId, addresses);
        log.info("Registered {} addresses for device {}", addresses.size(), deviceId);
    }
    
    /**
     * 批量读取PLC数据
     * 
     * @param channel 通信通道
     * @param deviceId 设备ID
     * @param unitId 单元ID
     */
    public void batchReadRegisters(Channel channel, String deviceId, byte unitId) {
        List<PlcAddress> addresses = deviceAddressMap.get(deviceId);
        if (addresses == null || addresses.isEmpty()) {
            log.warn("No addresses registered for device {}", deviceId);
            return;
        }
        
        // 分批读取，每批最多读取125个寄存器（Modbus限制）
        int batchSize = 125;
        int totalAddresses = addresses.size();
        int batches = (totalAddresses + batchSize - 1) / batchSize;
        
        log.info("Reading {} addresses in {} batches for device {}", totalAddresses, batches, deviceId);
        
        for (int i = 0; i < batches; i++) {
            int startIdx = i * batchSize;
            int endIdx = Math.min(startIdx + batchSize, totalAddresses);
            int count = endIdx - startIdx;
            
            // 找到这批地址的起始地址
            int startAddress = addresses.get(startIdx).getAddress();
            
            // 创建读取请求
            sendReadRequest(channel, unitId, startAddress, count, i);
        }
    }
    
    /**
     * 发送读取请求
     */
    private void sendReadRequest(Channel channel, byte unitId, int startAddress, int count, int batchIndex) {
        if (!channel.isActive()) {
            log.warn("Channel is not active, cannot send read request");
            return;
        }
        
        // 创建Modbus读取请求
        ModbusMessage request = new ModbusMessage();
        request.setTransactionId((short) transactionIdGenerator.incrementAndGet());
        request.setProtocolId((short) 0);
        request.setUnitId(unitId);
        request.setFunctionCode((byte) 3); // 读保持寄存器
        
        // 创建请求数据
        ByteBuf data = Unpooled.buffer(4);
        data.writeShort(startAddress);
        data.writeShort(count);
        request.setData(data);
        request.setLength((short) (data.readableBytes() + 2)); // +2 for unitId and functionCode
        
        // 发送请求
        channel.writeAndFlush(request);
        log.debug("Sent read request for {} registers starting at {}, batch {}", count, startAddress, batchIndex);
    }
    
    /**
     * 处理读取响应
     */
    public void handleReadResponse(ModbusMessage response, String deviceId) {
        ByteBuf data = response.getData();
        if (data == null || !data.isReadable()) {
            log.warn("Empty response data");
            return;
        }
        
        // 读取字节数
        int byteCount = data.readByte() & 0xFF;
        int registerCount = byteCount / 2;
        
        // 读取寄存器值
        Map<Integer, Integer> values = new HashMap<>();
        for (int i = 0; i < registerCount; i++) {
            int value = data.readShort() & 0xFFFF;
            values.put(i, value);
        }
        
        // 更新最新数据
        latestDataMap.put(deviceId, values);
        
        // 存储到InfluxDB
        storeToInfluxDB(deviceId, values);
    }
    
    /**
     * 存储数据到InfluxDB
     */
    private void storeToInfluxDB(String deviceId, Map<Integer, Integer> values) {
        List<Point> points = new ArrayList<>();
        long timestamp = System.currentTimeMillis();
        
        for (Map.Entry<Integer, Integer> entry : values.entrySet()) {
            int address = entry.getKey();
            int value = entry.getValue();
            
            Point point = Point.measurement("plc_data")
                    .time(timestamp, TimeUnit.MILLISECONDS)
                    .tag("deviceId", deviceId)
                    .tag("address", String.valueOf(address))
                    .addField("value", value)
                    .build();
            
            points.add(point);
        }
        
        // 批量写入
        influxDBService.writePoints(points);
        log.debug("Stored {} points for device {}", points.size(), deviceId);
    }
    
    /**
     * 定时采集任务
     */
    @Scheduled(fixedRate = 1000) // 每1秒执行一次
    public void scheduledCollection() {
        // 实际实现中，这里会遍历所有设备并触发数据采集
        log.debug("Scheduled collection triggered");
    }
    
    /**
     * 获取最新数据
     */
    public Map<Integer, Integer> getLatestData(String deviceId) {
        return latestDataMap.getOrDefault(deviceId, new HashMap<>());
    }
} 